package com.ilikesoup.instant.classifier;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.function.Predicate;

/**
 * @ClassName ListClassifier
 * @Description: 列表分类器
 * @Author gaoxiang
 * @Date 2020/8/7 11:50
 * @Version V1.0
 * 将列表按照分类器进行分类，然后对每个分类进行不同的处理
 *
 * 该类主要用来简化下列代码：
 * List<T> condition1 = new ArrayList<T>();
 * List<T> condition2 = new ArrayList<T>();
 * List<T> other = new ArrayList<T>();
 * for(T t : dataList) {
 *     if(underCondition1) {
 *         condition1.add(t);
 *     } else if(underConditon2) {
 *         condition2.add(t);
 *     } else {
 *         other.add(t);
 *     }
 * }
 * doSth1(condition1);
 * doSth2(condition2);
 * doSth3(other);
 *
 * =>
 * new ClassifierBuilder<T>()
 *  .onIf(t -> underCondition1Predicate(t), ActionBuilder.create(doSth1))
 *  .onIf(t -> underCondition2Predicate(t), ActionBuilder.create(doSth2))
 *  .onElse(ActionBuilder.create(doSth3)).classifyAndTrigger(dataList);
 *
 **/
public class Classifier<T> {
    /**
     * 分类器
     */
    private final List<Predicate<? super T>> classifiers;
    /**
     * 每个命中分类对应的动作，和 classifier 按顺序一一对应
     */
    private final List<Action<List<T>, ?>> ifActions;
    /**
     * 未命中分类对应的动作
     */
    private final Action<List<T>, ?> elseAction;

    public Classifier(List<Predicate<? super T>> classifiers, List<Action<List<T>, ?>> ifActions) {
        this.classifiers = classifiers;
        this.ifActions = ifActions;
        this.elseAction = null;
    }

    public Classifier(List<Predicate<? super T>> classifiers, List<Action<List<T>, ?>> ifActions, Action<List<T>, ?> elseAction) {
        this.classifiers = classifiers;
        this.ifActions = ifActions;
        this.elseAction = elseAction;
    }

    public List<List<T>> classify(List<? extends T> data) {
        return classify(data, classifiers);
    }

    public List<Object> classifyAndTrigger(List<? extends T> data) {
        List<Object> result = new ArrayList<>();
        List<List<T>> parts = classify(data);
        for (int i = 0; i < ifActions.size(); i++) {
            result.add(ifActions.get(i).trigger(parts.get(i)));
        }
        if(elseAction != null) {
            result.add(elseAction.trigger(parts.get(parts.size() - 1)));
        }
        return result;
    }

    /**
     * 将列表按照分类器进行划分，列表中的每项数据只能被划分到一类
     * 最终划分得到的分组数为 classifiers的长度 + 1
     * @param data
     * @param classifiers 其中的每一项都不能为 null，否则会抛出 NullPointerException
     * @param <T>
     * @return
     */
    public static <T> List<List<T>> classify(List<? extends T> data, Predicate<? super T>... classifiers) {
        return classify(data, classifiers == null || classifiers.length == 0 ? Collections.emptyList() : Arrays.asList(classifiers));
    }

    public static <T> List<List<T>> classify(List<? extends T> data, List<Predicate<? super T>> classifiers) {
        List<List<T>> partList = new ArrayList<>();
        if (classifiers == null || classifiers.size() == 0) {
            partList.add(new ArrayList<>(data));
            return partList;
        }
        int len = classifiers.size();
        // 数据列表会被分成 classifiers.length + 1 份
        for (int i = 0; i < len + 1; i++) {
            partList.add(new ArrayList<>());
        }
        // 进行筛分
        int i;
        out: for (T datum : data) {
            i = 0;
            for (; i < len; i++) {
                if (classifiers.get(i).test(datum)) {
                    partList.get(i).add(datum);
                    continue out;
                }
            }
            if (i == len) {
                partList.get(len).add(datum);
            }
        }
        return partList;
    }

}
